#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import re
import subprocess as p
import sys
import threading
from shutil import which
from time import sleep

STOP = re.compile(rb'\[Inferior \d+ \(process \d+\) exited normally\]')
RESULT = re.compile(rb'\(gdb\)')


def main(args: list[str]):
    args = [
        which('gdb'),
        '--args',
        *args,
    ]
    with p.Popen(
        args=args,
        stdin=p.PIPE,
        stdout=p.PIPE,
        stderr=p.STDOUT,
        text=False,
    ) as proc:
        stop = threading.Event()
        print_out = threading.Event()
        lock = threading.Lock()
        lock.acquire()
        stdin = proc.stdin
        assert stdin
        stdout = proc.stdout
        assert stdout

        def read():
            line = bytearray()
            while proc.poll() is None:
                data = proc.stdout.read(1)
                ch = data[0]
                if ch == ord('\r'):
                    continue
                if RESULT.match(line) and ch == ord(' '):
                    line = bytearray()
                    lock.release()
                    continue
                line.append(ch)
                if STOP.match(line):
                    stop.set()
                if ch == ord('\n'):
                    if print_out.is_set():
                        sys.stdout.write(line.decode())
                        sys.stdout.flush()
                    line = bytearray()
            pass

        def cmd(text: str, *, out: bool = False):
            lock.acquire()
            if out:
                print_out.set()
            else:
                print_out.clear()
            proc.stdin.write((text + '\n').encode())
            proc.stdin.flush()

        t = threading.Thread(target=read)
        t.start()
        sleep(1)
        cmd('set pagination 0')
        cmd('run &')
        while not stop.is_set():
            sleep(0.1)
            cmd('interrupt')
            if stop.is_set():
                break
            cmd('thread apply all bt', out=True)
            if stop.is_set():
                break
            cmd('continue &')
        cmd('exit')
        lock.release()
        proc.wait(1)
        proc.terminate()
        t.join()
    pass


if __name__ == '__main__':
    main(sys.argv[1:])
